<--- %%NOBANNER%% --> _ranmult.sas
 BackForward

/*-------------------<-- Start of Description -->--------------------\
| Generate multi-normial distrubtion;                                |
|--------------------<--- End of Description -->---------------------|
|--------------------------------------------------------------------|
|--------------<--- Start of Files or Arguments Needed -->-----------|
| Arguments required:                                                |
|    seed  - the seed; default is the system time;                   |
|       n  - the dimension of the output array;                      | 
|       p  - proportion table;                                       |
|       m  - the total size of the multi-normial distribution;       |
|     var  - the output var name or array names;                     |
| Other Arguments:                                                   |
|    temp1 - internal temporary variable;                            |
|    temp2 - internal temporary variable;                            |
|    init  - output the generated variates to an array;              |
|            if 1, create an array using the name of the "var"as     |
|            prefix;                                                 |
|            otherwise, the input variable "var" is an array, just   |
|            use it to save the generated variates;                  |
|---------------<--- End of Files or Arguments Needed -->------------|
|--------------------------------------------------------------------|
|----------------<--- Start of Example and Usage -->-----------------|
| Example:                                                           |
|    data one;                                                       |
|       array _p(3) (0.25, 0.5, 0.25);                               |
|       %_ranmult(seed=1, var=x, n=3, p=_p, m=5);                    |
|       put x1-x3 _cdf1-_cdf2 seed;                                  |
|       do i=1 to 100000;                                            |
|          %_ranmult(seed=seed, var=x, m=5, n=3, p=_p, init=0);      |
|          output;                                                   |
|       end;                                                         |
|    run; proc print data=one(obs=200); run;                         |
|    proc freq data=one;                                             |
|       tables x1-x3 / list missing;                                 |
|    run;                                                            |
| Usage: %_ranmult(seed=%sysfunc(datetime(), 15.), var=, n=, p=, m=, |
|                  temp1=_temp1, temp2=_temp2, init=1);              |
\-------------------<--- End of Example and Usage -->---------------*/
%macro _ranmult(seed=%sysfunc(datetime(), 15.), var=, n=, p=, m=, 
                temp=_ranseed0_, temp1=_temp1, temp2=_temp2, init=1);
/*--------------------------------------------\
| Author:   Duo Zhou;                         |
| Created:  3-23-2001 9:12pm;                 |
| Purpose:  Random Multi-normial Generator;   |
\--------------------------------------------*/
%if (%quote(&seed) eq) or (%quote(&var) eq) or (%quote(&n) eq) or (%quote(&m) eq) or (%quote(&p) eq) %then %do;
  %if (%quote(&seed) eq) %then %do;
     %put ==> Error: This is not a valid seed!; 
     %if (%length(&var)) %then %do; &var=.; %end;
  %end;
  %if (%quote(&var) eq) %then %do;
     %put ==> Error: This function will need a valid array to save the generated random;
     %put +++        variates!; 
     %if (%length(&var)) %then %do; &var=.; %end;
  %end;
  %if (%quote(&n) eq) %then %do;
     %put ==> Error: I will save the generated random variates into the array "&var", so;
     %put +++        please provide array dimension !; 
     %if (%length(&var)) %then %do; &var=.; %end;
  %end;
  %if (%quote(&p) eq) %then %do;
     %put ==> Error: I need a valid proportion or proportion array!; 
     %if (%length(&var)) %then %do; &var=.; %end;
  %end;
  %if (%quote(&m) eq) %then %do;
     %put ==> Error: I need a total size for multi-normal distribution!; 
     %if (%length(&var)) %then %do; &var=.; %end;
  %end;
  %goto finish;
%end;       
%if (not %sysfunc(rxmatch(%sysfunc(rxparse(_|.|$a|$A|$w)),&seed))) %then %do;
      drop &temp;
      retain &temp &seed;
      %let seed=&temp;
%end;
%if &init %then %do;
	array &var(&n) &var.1 - &var.%left(&n);
%end;
do &temp1=1 to &n;
   &var(&temp1)=0;
end;

do &temp1=1 to &m;
   %_rantbl(seed=&seed, var=&temp2, n=&n, p=&p, init=&init);
   &var(&temp2)=&var(&temp2)+1;
end;
%finish:
%mend _ranmult;